package cn.com.dhcc.app.pub.core.util.settlement.compute.store;

import cn.com.dhcc.app.pub.core.util.settlement.compute.configuation.ComputeConfiguation;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;


/**
 * 默认的数据处理器，主要用来临时存数据，移动数据，还有就是读数据
 * @author Administrator
 *
 */
public class DefaultDataProcessHandler extends ComputeConfiguation implements DataProcessHandler{


	/**
	 * 临时存储数据的文件
	 * @param orderId
	 * @param tableName
	 * @param group
	 * @return
	 */
	private File tempStoreFile(String orderId,String tableName,int group){
		File orderDir=new File(TEMP_Dir,orderId);
		File tableDir=new File(orderDir,tableName);
		if (!tableDir.exists()) {
			tableDir.mkdirs();
		}
		return new File(tableDir,group+DATA_SUFFIX);
	}
	
	/**
	 * 结算数据的文件
	 * @param orderId
	 * @param tableName
	 * @param group
	 * @return
	 */
	private File computeFile(String cdate,String taskId,String tableName,int group){
		File taskDir = new File(new File(FINAL_DIR,cdate),taskId);
		File tableDir = new File(taskDir,tableName);
		return new File(tableDir,group+DATA_SUFFIX);
	}
	

	@Override
	public void store(String orderId,String tableName, List<List<String>> datas) throws IOException {
		System.out.println("存储任务开始,任务orderid["+orderId+"],表["+tableName+"]");
		//循环分组存储
		for (int i=0;i<datas.size();i++) {
			File file=tempStoreFile(orderId, tableName, i);
			List<String> data=datas.get(i);
			FileUtils.writeLines(file, DEFAULT_ENCODING,data , true);
			System.out.println("存储任务开始,任务orderid["+orderId+"],表["+tableName+"],组["+i+"]存储了["+data.size()+"]条数据");
		}
	}

	@Override
	public void merge(String orderId, String taskId,Date date) throws IOException {
		//首先找到临时储存的所有表--从orderid中查找
		File orderDir=new File(TEMP_Dir,orderId);
		String[] tables=orderDir.list();//文件名即表名
		String cdate = SDF_FORMAT.format(date);//结算日期 格式为yyyyMMDD 
		if (tables!=null && tables.length>0) {
			for (String table : tables) {
				File taskDir = new File(new File(FINAL_DIR,cdate),taskId);//对应的结算目录
				File cfile=new File(taskDir,table);//对应的结算目录
				if (!cfile.exists()) {//说明还没有对应的结算数据，直接移动整个临时表目录
					FileUtils.moveDirectory(orderDir, taskDir);//直接整个目录拷贝进去
				}else{
					mergeDir(new File(orderDir,table), cfile);//合并整个表目录
				}
			}
		}
		
		//删除整个请求的目录
		try {
			FileUtils.deleteDirectory(orderDir);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}

	/**
	 * 目录合并--里面的文件也合并
	 * @param srcDir
	 * @param destDir
	 * @throws IOException
	 */
	private void mergeDir(File srcDir,File destDir) throws IOException{
		File[] srcFiles=srcDir.listFiles();
		if (srcFiles!=null && srcFiles.length>0) {
			for (File srcfile : srcFiles) {
				File destFile=new File(destDir,srcfile.getName());
				if (destFile.exists()) {//存在，就追加
					//将数据追加到对应的文件后面
					FileUtils.writeLines(destFile,DEFAULT_ENCODING, FileUtils.readLines(srcfile,DEFAULT_ENCODING), true);
				}else{
					FileUtils.moveFile(srcfile, destFile);//否则则移动文件
				}
			}
		}
	}
	
	
	@Override
	public void delete(String orderId) throws IOException {
		FileUtils.deleteDirectory(new File(TEMP_Dir,orderId));//删除整个发送请求 目录
	}

	public List<String> read(String cdate,String taskId, String tableName,int group) throws IOException {
		File file=computeFile(cdate,taskId, tableName, group);
		if (file.exists()) {//如果存在就读
			return FileUtils.readLines(file, DEFAULT_ENCODING);
		}
		
		return new ArrayList<String>();
	}

	public static void main(String[] args) {
		File file=new File("D:\\aaa");
		String[] fs=file.list();
		for (String string : fs) {
			System.out.println(string);
		}
		
	}

	/**
	 * 存储结算结果
	 * @param taskId
	 * @param tableName
	 * @throws IOException 
	 */
	private void storeResult(String cdate,String taskId,String tableName,List<String> data) throws IOException{
		
		File dateDir=new File(COMPUTE_DIR,cdate);
		File taskDir=new File(dateDir,taskId);
		if (!taskDir.exists()) {
			taskDir.mkdirs();
		}
		File file=new File(taskDir,tableName+COMPUTE_RESULT_SUFFIX);//结算结果
		FileUtils.writeLines(file, DEFAULT_ENCODING, data, true);
		
	}
	
	/**
	 * 存储结算结果映射信息--根据索引查找
	 * @param taskId
	 * @param tableName
	 * @throws IOException 
	 */
	private void storeMapping(String cdate,String taskId,String tableName,List<String> data) throws IOException{
		
		File dateDir=new File(COMPUTE_MAPPING_DIR,cdate);
		File taskDir=new File(dateDir,taskId);
		if (!taskDir.exists()) {
			taskDir.mkdirs();
		}
		File file=new File(taskDir,tableName+COMPUTE_MAPPING_SUFFIX);//结算结果
		FileUtils.writeLines(file, DEFAULT_ENCODING, data, true);
		
	}
	
			
	
	
	
	@Override
	public int compute(String taskId, String tableName,DataGroupVo vo,Date date) throws IOException {
		//循环要结算的数据
		int group=vo.getGroup();
		String cdate=SDF_FORMAT.format(date);//结算日期 格式为yyyyMMDD 
		int sum = 0;
		for (int i=0;i<group;i++) {
			List<List<String>> datas = vo.getHashList();
			System.out.println("开始结算taskId["+taskId+"],tableName["+tableName+"],group["+group+"]");
			//结算
			List<String> src = datas.get(i);
			List<String> dest = read(cdate,taskId,tableName,i);
			List<String> sub = (List<String>) CollectionUtils.subtract(src, dest);
			//存储结果
			storeResult(cdate,taskId, tableName,sub);
			sum += sub.size();
			//存储映射结果
			List<String> mapping = vo.mapping(i,sub);
			storeMapping(cdate,taskId, tableName,mapping);
			System.out.println("结算taskId["+taskId+"],tableName["+tableName+"],group["+group+"]结束，" +
					"结算结果,源["+src.size()+"]条,已交换["+dest.size()+"],差集["+sub.size()+"]条,映射结果["+mapping.size()+"]条");
		}
		return sum;
	}

	
	@Override
	public ComputeResultVo loadResult(String taskId, String tableName, Date computeDate) throws IOException {
		ComputeResultVo vo=new ComputeResultVo();
		String cdate=SDF_FORMAT.format(computeDate);
		File hF=new File(new File(COMPUTE_DIR,cdate),taskId);//结算目录
		File sF=new File(new File(COMPUTE_MAPPING_DIR,cdate),taskId);//映射目录
		
		File hdF=new File(hF,tableName+COMPUTE_RESULT_SUFFIX);//找到结算文件
		if (hdF.exists()) {//如果存在就读取
			vo.addHashList(FileUtils.readLines(hdF, DEFAULT_ENCODING));
			//接下来也必须有映射数据文件
			File sdF=new File(sF,tableName+COMPUTE_MAPPING_SUFFIX);
			vo.addSrcList(FileUtils.readLines(sdF,DEFAULT_ENCODING));
		}
		
		return vo;
	}

}
